/*
 * Copyright (c) 2020-2099 the original author or authors. All rights reserve.
 */
package org.tianyun.cloud.data.redis.autoconfigure;

import org.springframework.beans.factory.ObjectProvider;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.tianyun.cloud.config.refresh.smart.annotation.SmartScope;
import org.tianyun.cloud.data.redis.RedisConnectionFactoryConfigurer;
import org.tianyun.cloud.data.redis.RedisContainerPostProcessor;
import org.tianyun.cloud.data.redis.RedisContainerRegistrar;
import org.tianyun.cloud.data.redis.annotation.RedisContainer;
import org.tianyun.cloud.data.redis.cache.action.CacheAction;
import org.tianyun.cloud.data.redis.cache.action.DefualtCacheActionHandler;
import org.tianyun.cloud.data.redis.cache.action.FlushCacheAction;
import org.tianyun.cloud.data.redis.cache.action.SetCacheAction;
import org.tianyun.cloud.data.redis.cache.action.TryLockAction;
import org.tianyun.cloud.data.redis.cache.aspect.FlushCacheAspect;
import org.tianyun.cloud.data.redis.cache.aspect.SetCacheAspect;
import org.tianyun.cloud.data.redis.cache.aspect.TryLockAspect;
import org.tianyun.cloud.data.redis.configuration.RedisCacheProperties;
import org.tianyun.cloud.data.redis.configuration.RedisContainerProperties;
import org.tianyun.cloud.data.redis.factory.ObjectRedisTemplate;

import java.util.List;

/**
 * Redis自动配置
 *
 * @auther ebert_chan
 */
@Configuration(proxyBeanMethods = false)
@Import(RedisContainerRegistrar.class)
public class RedisContainerAutoConfiguration {

    public static final String REDIS_CONNECTION_FACTORY_BEAN = "redisConnectionFactory";

    public static final String REDIS_TEMPLATE_BEAN = "redisTemplate";

    public static final String STRING_REDIS_TEMPLATE_BEAN = "stringRedisTemplate";

    public static final String REACTIVE_REDIS_TEMPLATE_BEAN = "reactiveRedisTemplate";

    public static final String REACTIVE_STRING_REDIS_TEMPLATE_BEAN = "reactiveStringRedisTemplate";

    // @formatter:off
	public static final String[] REMOVE_BEAN_NAMES = {
            REACTIVE_STRING_REDIS_TEMPLATE_BEAN,
            REACTIVE_REDIS_TEMPLATE_BEAN,
            STRING_REDIS_TEMPLATE_BEAN,
            REDIS_TEMPLATE_BEAN,
			REDIS_CONNECTION_FACTORY_BEAN
	};
	// @formatter:on

    @RedisContainer(prefix = "redis.common", primary = true,
            connectionFactory = REDIS_CONNECTION_FACTORY_BEAN,
            redisTemplate = REDIS_TEMPLATE_BEAN, stringRedisTemplate = STRING_REDIS_TEMPLATE_BEAN,
            reactiveRedisTemplate = REACTIVE_REDIS_TEMPLATE_BEAN,
            reactiveStringRedisTemplate = REACTIVE_STRING_REDIS_TEMPLATE_BEAN,
            objectRedisTemplate = "objectRedisTemplate"
    )
    public RedisContainerProperties commonRedisContainerProperties() {
        return new RedisContainerProperties();
    }

    @Bean
    public static RedisContainerPostProcessor redisContainerPostProcessor(ObjectProvider<List<RedisConnectionFactoryConfigurer>> redisConnectionFactoryConfigurerProvider) {
        return new RedisContainerPostProcessor(redisConnectionFactoryConfigurerProvider);
    }

    @Bean
    @SmartScope("redis.cache")
    @ConfigurationProperties(prefix = "redis.cache", ignoreInvalidFields = true)
    public RedisCacheProperties redisCacheProperties() {
        return new RedisCacheProperties();
    }

    @Bean
    @ConditionalOnMissingBean(CacheAction.class)
    public DefualtCacheActionHandler defualtCacheActionHandler(RedisCacheProperties redisCacheProperties, ObjectProvider<ObjectRedisTemplate> objectRedisTemplateProvider) {
        return new DefualtCacheActionHandler(redisCacheProperties, objectRedisTemplateProvider);
    }

    @Bean
    public SetCacheAspect setCacheAspect(SetCacheAction action) {
        return new SetCacheAspect(action);
    }

    @Bean
    public FlushCacheAspect flushCacheAspect(FlushCacheAction action) {
        return new FlushCacheAspect(action);
    }

    @Bean
    public TryLockAspect tryLockAspect(TryLockAction action) {
        return new TryLockAspect(action);
    }

}
